package com.fakeDYChat.common.websocket;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.fakeDYChat.common.common.utils.NettyUtil;
import com.fakeDYChat.common.websocket.service.WebSocketService;
import com.fakeDYChat.common.websocket.domain.enums.WSReqTypeEnum;
import com.fakeDYChat.common.websocket.domain.vo.req.WSBaseReq;
import io.netty.channel.ChannelHandler.*;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;


//加上Sharable注解的目的是：该处理器可以被复用，且是无状态的。
@Slf4j
@Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private WebSocketService webSocketService;

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        webSocketService = getService();
    }


    /**
     * 用户主动下线
     *
     * @param ctx
     * @return void
     * @author Tang
     * @date 2023/12/10 15:43
     **/
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("用户下线 - {}", ctx.channel().id());
        userOffline(ctx);
    }

    /**
     * 事件监听器
     *
     * @param ctx
     * @param evt
     * @return void
     * @author Tang
     * @date 2023/12/14 8:49
     **/
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            //保存Netty连接通道
            userConnect(ctx);
            //获取token
            String token = NettyUtil.getAttr(ctx.channel(), NettyUtil.TOKEN);
            if (StringUtils.isNoneBlank(token)) {
                webSocketService.authorized(ctx, token);
            }
        } else if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            if (idleStateEvent.state() == IdleState.READER_IDLE) {
                log.warn(ctx.name() + "读空闲");
                //todo 下线
                userOffline(ctx);
            }
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws WxErrorException {
        String text = msg.text();
        if (StringUtils.isEmpty(text)) {
            return;
        }
        WSBaseReq req = JSONUtil.toBean(text, WSBaseReq.class);
        switch (WSReqTypeEnum.of(req.getType())) {
            case LOGIN:
                log.info("用户请求登录");
                webSocketService.handleLoginReq(ctx);
                ctx.channel().writeAndFlush(new TextWebSocketFrame("二维码"));
                break;
            case HEARTBEAT:
                break;
            case AUTHORIZE:
                log.info("用户请求认证");
                webSocketService.authorized(ctx, req.getData());
                break;
        }
    }

    private WebSocketService getService() {
        return SpringUtil.getBean(WebSocketService.class);
    }

    private void userConnect(ChannelHandlerContext ctx) {
        webSocketService.connect(ctx);
    }

    private void userOffline(ChannelHandlerContext ctx) {
        log.info("用户下线-{}", ctx);
        webSocketService.offline(ctx);
        ctx.channel().close();
    }

}
